/**
 * 支付服务实现类 - 处理支付订单的核心业务逻辑
 *
 * 开发人员：徐少洋
 * 开发时间：2025-11-08 至 2025-11-12
 * 模块职责：实现支付订单的创建、查询、状态管理等核心业务逻辑，与ZPAY支付平台对接
 *
 * 技术要点：
 * - 支付订单全生命周期管理
 * - ZPAY支付接口集成和签名验证
 * - 多租户数据隔离和权限控制
 * - 订单状态机和业务规则处理
 * - 异常处理和事务管理机制
 *
 * 开发故事：负责支付服务的核心业务逻辑实现，与支付控制器和ZPAY支付平台深度集成，确保支付流程的稳定性和安全性。
 */
package com.pbl.service.impl;

import com.pbl.common.enums.PaymentStatus;
import com.pbl.common.exception.BizException;
import com.pbl.config.props.ZpayProps;
import com.pbl.entity.Enterprise;
import com.pbl.entity.PaymentOrder;
import com.pbl.entity.Product;
import com.pbl.entity.User;
import com.pbl.repository.EnterpriseRepository;
import com.pbl.repository.PaymentOrderRepository;
import com.pbl.repository.ProductRepository;
import com.pbl.repository.UserRepository;
import com.pbl.service.PaymentService;
import com.pbl.util.IdGenerator;
import com.pbl.util.ZpaySignUtil;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service
public class PaymentServiceImpl implements PaymentService {

    private final PaymentOrderRepository paymentOrderRepository;
    private final EnterpriseRepository enterpriseRepository;
    private final UserRepository userRepository;
    private final ProductRepository productRepository;
    private final ZpayProps zpayProps;

    public PaymentServiceImpl(PaymentOrderRepository paymentOrderRepository, EnterpriseRepository enterpriseRepository, UserRepository userRepository, ProductRepository productRepository, ZpayProps zpayProps) {
        this.paymentOrderRepository = paymentOrderRepository;
        this.enterpriseRepository = enterpriseRepository;
        this.userRepository = userRepository;
        this.productRepository = productRepository;
        this.zpayProps = zpayProps;
    }

    @Override
    public PaymentOrder createOrder(Long enterpriseId, Long userId, String name, BigDecimal amount, String payType) {
        Enterprise ent = enterpriseRepository.findById(enterpriseId).orElseThrow(() -> new BizException(404, "企业不存在"));
        User user = null;
        if (userId != null) {
            user = userRepository.findById(userId).orElse(null);
        }
        PaymentOrder po = new PaymentOrder();
        po.setEnterprise(ent);
        po.setUser(user);
        po.setName(name);
        po.setAmount(amount);
        po.setPayType(payType);
        po.setStatus(PaymentStatus.CREATED);
        po.setOutTradeNo(IdGenerator.generateOutTradeNo());
        return paymentOrderRepository.save(po);
    }

    @Override
    public PaymentOrder createOrderWithProduct(Long enterpriseId, Long userId, Long productId, String name, BigDecimal amount, String payType) {
        Enterprise ent = enterpriseRepository.findById(enterpriseId).orElseThrow(() -> new BizException(404, "企业不存在"));
        User user = null;
        if (userId != null) {
            user = userRepository.findById(userId).orElse(null);
        }
        Product product = null;
        if (productId != null) {
            product = productRepository.findById(productId).orElse(null);
        }
        
        PaymentOrder po = new PaymentOrder();
        po.setEnterprise(ent);
        po.setUser(user);
        po.setProduct(product);
        po.setName(name);
        po.setAmount(amount);
        po.setPayType(payType);
        po.setStatus(PaymentStatus.CREATED);
        po.setOutTradeNo(IdGenerator.generateOutTradeNo());
        return paymentOrderRepository.save(po);
    }

    @Override
    public PaymentOrder getByOutTradeNo(String outTradeNo) {
        return paymentOrderRepository.findByOutTradeNo(outTradeNo).orElseThrow(() -> new BizException(404, "订单不存在"));
    }

    @Override
    public PaymentOrder markSuccess(String outTradeNo, String tradeNo) {
        PaymentOrder po = getByOutTradeNo(outTradeNo);
        po.setTradeNo(tradeNo);
        po.setStatus(PaymentStatus.SUCCESS);
        po.setPaidAt(java.time.LocalDateTime.now());
        PaymentOrder saved = paymentOrderRepository.save(po);
        
        // 重新查询以避免懒加载代理问题
        return paymentOrderRepository.findById(saved.getId()).orElse(saved);
    }

    @Override
    public PaymentOrder closeOrder(String outTradeNo) {
        PaymentOrder po = getByOutTradeNo(outTradeNo);
        po.setStatus(PaymentStatus.CLOSED);
        po.setClosedAt(java.time.LocalDateTime.now());
        PaymentOrder saved = paymentOrderRepository.save(po);
        
        // 重新查询以避免懒加载代理问题
        return paymentOrderRepository.findById(saved.getId()).orElse(saved);
    }

    @Override
    public Map<String, String> buildZpayParams(String outTradeNo, String type, String name, String amount, String notifyUrl, String returnUrl) {
        Map<String, String> params = new HashMap<>();
        params.put("pid", zpayProps.getPid());
        params.put("type", type);
        params.put("out_trade_no", outTradeNo);
        params.put("notify_url", notifyUrl == null ? zpayProps.getNotifyUrl() : notifyUrl);
        params.put("return_url", returnUrl == null ? zpayProps.getReturnUrl() : returnUrl);
        params.put("name", name);
        params.put("money", amount);
        params.put("sign_type", "MD5");
        String sign = ZpaySignUtil.buildSign(params, zpayProps.getPkey());
        params.put("sign", sign);
        // 模拟支付url（不真实发起），供前端跳转演示
        params.put("payurl", zpayProps.getBaseUrl() + "/submit.php?" + ZpaySignUtil.toQueryString(params, false));
        return params;
    }
}
